/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package ConexionesBD;

import Esquemas.Atributo;
import Esquemas.Entidad;
import Esquemas.EntidadDebil;
import Esquemas.Esquema;
import Esquemas.Participa;
import Esquemas.Relacion;
import Esquemas.RelacionEspecificacion;
import java.sql.Statement;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.ArrayList;
import oracle.jdbc.OracleConnection;
import oracle.jdbc.OracleResultSet;

/**
 *
 * @author Carmen M. Morillo Arias, Christian Neria Suárez, Diego Ojeda García
 */
public class conexionBD {
    
    OracleConnection con;
    
    /**
     * Conexión con la base de datos
     * @throws SQLException 
     */
    public void conectar() throws SQLException {
        this.con = (OracleConnection) DriverManager.getConnection("jdbc:oracle:thin:inftel13_20/m4bd@olimpia.lcc.uma.es:1521:edgar");        
    }
    
    /**
     * Obtiene un esquema
     * @throws SQLException 
     */
    public void obtenerEsquema() throws SQLException{
        this.con = (OracleConnection) DriverManager.getConnection("jdbc:oracle:thin:inftel13_20/m4bd@olimpia.lcc.uma.es:1521:edgar");
        Statement stmt = (Statement) con.createStatement();
        OracleResultSet rs = (OracleResultSet) stmt.executeQuery("SELECT * FROM esquema");
        
        System.out.println("***** ESQUEMAS DEL USUARIO *****");
        while (rs.next())
        {
            System.out.println ("   " + rs.getString(1));
            
        }
        stmt.close();
    }
    
    /**
     * Obtiene todos los tipos de datos para un esquema dado
     * @param esquema Esquema
     * @throws SQLException 
     */
    public void obtenerTiposDatosEsquema(Esquema esquema) throws SQLException{
        Statement stmt = (Statement) con.createStatement();
        Statement stmtAttr = (Statement) con.createStatement();
        
        //Entidades fuertes
        OracleResultSet rs = (OracleResultSet) stmt.executeQuery("(SELECT nombre "
                                                                + "FROM tipo_entidad "
                                                                + "WHERE nombre_esquema='" + esquema.getNombre()+"')"
                                                                + "MINUS"
                                                                + "(SELECT nombre "
                                                                + "FROM tipo_entidad_debil "
                                                                + "WHERE nombre_esquema='"+esquema.getNombre()+"')");
        OracleResultSet rsAttrs;
        Entidad ef;
        while (rs.next())
        {
            ef = new Entidad(rs.getString(1));            
            rsAttrs = (OracleResultSet) stmtAttr.executeQuery("SELECT * FROM atributos WHERE nombre_tipos_de_datos = '" + ef.getNombre() + "' AND nombre_esquema = '" + esquema.getNombre() + "'");
            while (rsAttrs.next()){
                ef.anadirAtributo(new Atributo(rsAttrs.getString("nombre"), rsAttrs.getString("nombre_tipos_de_datos"), rsAttrs.getString("nombre_esquema"),
                        rsAttrs.getBoolean("multivaluado"), rsAttrs.getBoolean("derivado"), rsAttrs.getString("tipo"),
                        rsAttrs.getString("nombre_atributo_compuesto")));
            }
            esquema.anadirTipodeDato(ef);
        }
        //Relaciones
        rs = (OracleResultSet) stmt.executeQuery("(SELECT nombre FROM tipo_relacion WHERE nombre_esquema='"+esquema.getNombre()+"')MINUS(SELECT nombre FROM tipo_rel_ident WHERE nombre_esquema='"+esquema.getNombre()+"')");
        Relacion r;
        while (rs.next())
        {
            r = new Relacion(rs.getString(1));
            rsAttrs = (OracleResultSet) stmtAttr.executeQuery("SELECT * FROM atributos WHERE nombre_tipos_de_datos = '" + r.getNombre() + "' AND nombre_esquema = '" + esquema.getNombre() + "'");
            while (rsAttrs.next()){
                r.anadirAtributo(new Atributo(rsAttrs.getString("nombre"), rsAttrs.getString("nombre_tipos_de_datos"), rsAttrs.getString("nombre_esquema"),
                        rsAttrs.getBoolean("multivaluado"), rsAttrs.getBoolean("derivado"), rsAttrs.getString("tipo"),
                        rsAttrs.getString("nombre_atributo_compuesto")));
            }
            esquema.anadirTipodeDato(r);
        }
        //Entidades débiles
        rs = (OracleResultSet) stmt.executeQuery("SELECT * FROM tipo_entidad_debil WHERE nombre_esquema='"+esquema.getNombre()+"'");
        EntidadDebil ed;
        while (rs.next())
        {
            ed= new EntidadDebil(rs.getString(1));
            rsAttrs = (OracleResultSet) stmtAttr.executeQuery("SELECT * FROM atributos WHERE nombre_tipos_de_datos = '" +ed.getNombre() + "' AND nombre_esquema = '" + esquema.getNombre() + "'");
            while (rsAttrs.next()){
                ed.anadirAtributo(new Atributo(rsAttrs.getString("nombre"), rsAttrs.getString("nombre_tipos_de_datos"), rsAttrs.getString("nombre_esquema"),
                        rsAttrs.getBoolean("multivaluado"), rsAttrs.getBoolean("derivado"), rsAttrs.getString("tipo"),
                        rsAttrs.getString("nombre_atributo_compuesto")));
            }
            esquema.anadirTipodeDato(ed);
        }                
        //Relaciones de especificación de entidades débiles
        rs = (OracleResultSet) stmt.executeQuery("SELECT nombre FROM tipo_rel_ident WHERE nombre_esquema='"+esquema.getNombre()+"'");
        RelacionEspecificacion re;
        while (rs.next())
        {
            re= new RelacionEspecificacion(rs.getString(1));
            rsAttrs = (OracleResultSet) stmtAttr.executeQuery("SELECT * FROM atributos WHERE nombre_tipos_de_datos = '" + re.getNombre() + "' AND nombre_esquema = '" + esquema.getNombre() + "'");
            while (rsAttrs.next()){
                re.anadirAtributo(new Atributo(rsAttrs.getString("nombre"), rsAttrs.getString("nombre_tipos_de_datos"), rsAttrs.getString("nombre_esquema"),
                        rsAttrs.getBoolean("multivaluado"), rsAttrs.getBoolean("derivado"), rsAttrs.getString("tipo"),
                        rsAttrs.getString("nombre_atributo_compuesto")));
            }
            esquema.anadirTipodeDato(re);
        }        
        stmt.close();
    }
    
    /**
     * Obtiene la tabla participaciones para un esquema dado
     * @param e Esquema
     * @return ArrayList con las participaciones
     * @throws SQLException 
     */
    public ArrayList<Participa> obtenerParticipaciones(Esquema e) throws SQLException {
        ArrayList<Participa> participaciones = new ArrayList<Participa>();
        Statement stmt = (Statement) con.createStatement();
        OracleResultSet rs = (OracleResultSet) stmt.executeQuery("Select * FROM participa WHERE nombre_esquema = '" + e.getNombre() + "'");
        while(rs.next()){
            Participa p = new Participa(rs.getString("nombre_entidad"), rs.getString("nombre_relacion"), 
                    rs.getString("nombre_esquema"), rs.getString("papel"), rs.getString("min"), rs.getString("max"));
            participaciones.add(p);
        }
        return participaciones;
    }

    /**
     * Obtiene la clave para una entidad dada en un esquema
     * @param entidad Entidad de la que se quiere obtener su clave
     * @param esquema Esquema al que pertenece la entidad
     * @throws SQLException 
     */
    public void obtenerClaveEntidad(Entidad entidad, Esquema esquema) throws SQLException{        
        Statement stmt = (Statement) con.createStatement();        
        OracleResultSet rs = (OracleResultSet) stmt.executeQuery("SELECT * FROM atributos WHERE nombre_tipo_entidad='"+entidad.getNombre()+"' AND nombre_esquema='"+esquema.getNombre()+"'");
        
        Atributo c;
        while(rs.next()){
            c = new Atributo(rs.getString("nombre"), rs.getString("nombre_tipos_de_datos"), rs.getString("nombre_esquema"),
                        rs.getBoolean("multivaluado"), rs.getBoolean("derivado"), rs.getString("tipo"),
                        rs.getString("nombre_atributo_compuesto"));              
            entidad.setClave(c);                          
        }                        
    }
        
    /**
     * Obtiene la clave parcial para una entidad débil
     * @param entidad Entidad débil
     * @param esquema Esquema al que pertenece la entidad débil
     * @throws SQLException 
     */
    public void obtenerClaveParcialEntidadDebil(EntidadDebil entidad, Esquema esquema) throws SQLException{
        Statement stmt = (Statement) con.createStatement();        
        OracleResultSet rs = (OracleResultSet) stmt.executeQuery("SELECT * "
                                                                +"FROM atributos a, tipo_entidad_debil ed "
                                                                +"WHERE a.nombre_esquema='"+esquema.getNombre()+"' AND "
                                                                +"ed.nombre_esquema='"+esquema.getNombre()+"' AND "
                                                                +"a.nombre_tipo_entidad_debil='"+entidad.getNombre()+"' AND "
                                                                +"a.nombre_tipo_entidad_debil=ed.nombre");
        Atributo c;
        while(rs.next()){
            c = new Atributo(rs.getString("nombre"), rs.getString("nombre_tipos_de_datos"), rs.getString("nombre_esquema"),
                        rs.getBoolean("multivaluado"), rs.getBoolean("derivado"), rs.getString("tipo"),
                        rs.getString("nombre_atributo_compuesto"));  
                        
            entidad.setClaveParcial(c);                          
        }        
    }
    
    /**
     * Obtener todas aquellas entidades fuertes que se relacionan con una entidad débil
     * @param entidad Entidad débil
     * @param esquema Esquema al que pertenecen
     * @param relacion Relación de especificación que identifica la entidad débil
     * @return ArrayList con los nombres de las entidades fuertes para esa entidad débil
     * @throws SQLException 
     */
    public ArrayList<String> obtenerClavesEntidadDebil(EntidadDebil entidad, Esquema esquema, RelacionEspecificacion relacion) throws SQLException{        
        ArrayList<String> entidadesFuertes = new ArrayList<String>();
        //Obtengo el nombre de las entidades que participan en la relación, excepto la entidad débil
        Statement stmt = (Statement) con.createStatement();
        OracleResultSet rs = (OracleResultSet) stmt.executeQuery("SELECT nombre_entidad "
                                                                +"FROM participa "
                                                                +"WHERE nombre_relacion='"+relacion.getNombre()+"' AND "
                                                                +"nombre_entidad<>'"+entidad.getNombre()+"' AND "
                                                                +"nombre_esquema='"+esquema.getNombre()+"'");              
        while(rs.next()){
            entidadesFuertes.add(rs.getString(1));
        }
        
        return entidadesFuertes;        
    }
    
    /**
     * Obtener todas las relaciones de especificación en las que participa una entidad débil
     * @param entidad Entidad débil
     * @param esquema Esquema al que pertenecen los datos
     * @return ArrayList de todas las relaciones en las que participa una entidad débil
     * @throws java.sql.SQLException
     */
    public ArrayList<String> obtenerRelacionesEspecificacionEntidadDebil(EntidadDebil entidad, Esquema esquema) throws SQLException{
        ArrayList<String> relacionesEspecificacion = new ArrayList<String>();
        relacionesEspecificacion.clear();
        Statement stmt = (Statement) con.createStatement();
        OracleResultSet rs = (OracleResultSet) stmt.executeQuery("SELECT ri.nombre "
                                                                +"FROM tipo_rel_ident ri, participa p "                                                                
                                                                +"WHERE p.nombre_entidad='"+entidad.getNombre()+"' AND "
                                                                +"p.nombre_relacion = ri.nombre AND "
                                                                +"p.nombre_esquema='"+esquema.getNombre()+"' AND "
                                                                +"ri.nombre_esquema='"+esquema.getNombre()+"'");        
        while(rs.next()){            
            relacionesEspecificacion.add(rs.getString(1));            
        }   
        return relacionesEspecificacion;
    }
    
    /**
     * Obtiene la cardinalidad de una entidad en una relación
     * @param entidad Entidad 
     * @param esquema Esquema al que pertenecen
     * @param relacion Relación
     * @return Cardinalidad de la entidad en la relación: 0,1,...,N
     * @throws SQLException 
     */
    public String obtenerCardinalidad(Entidad entidad, Esquema esquema, Relacion relacion) throws SQLException{
        String cardinalidad = null;
        Statement stmt = (Statement) con.createStatement();             
        OracleResultSet rs = (OracleResultSet) stmt.executeQuery("SELECT  max "
                                                                +"FROM participa "
                                                                +"WHERE nombre_esquema='"+esquema.getNombre()+"' AND "
                                                                +"nombre_entidad='"+entidad.getNombre()+"' AND "
                                                                +"nombre_relacion='"+relacion.getNombre()+"'");
        
        while(rs.next()){
            cardinalidad = rs.getString(1);
            
        }        
        return cardinalidad;
    }
    
    /**
     * Calcula si una entidad es aislada en un esquema (aquellas que no se relacionan con otras) o no
     * @param entidad Entidad de la que se quiere comprobar si es aislada
     * @param esquema Esquema al que pertenece
     * @return número de relaciones de la entidad
     * @throws SQLException 
     */
    public int obtenerEntidadAislada(Entidad entidad, Esquema esquema) throws SQLException{
        int veces=0;
        Statement stmt = (Statement) con.createStatement();             
        OracleResultSet rs = (OracleResultSet) stmt.executeQuery("SELECT  COUNT(*) "
                                                                +"FROM participa "
                                                                +"WHERE nombre_esquema='"+esquema.getNombre()+"' AND "
                                                                +"nombre_entidad='"+entidad.getNombre()+"'");
        
        while(rs.next()){
            veces = Integer.parseInt(rs.getString(1));
            
        }        
        return veces;    
    }              
}

